package com.boyinet.imesh2json.netty.policy

import java.util.*

class ExponentialBackOffRetry @JvmOverloads constructor(
    baseSleepTimeMs: Int,
    private val maxRetries: Int,
    maxSleepMs: Int = DEFAULT_MAX_SLEEP_MS
) : RetryPolicy {

    private val random: Random = Random()
    private val baseSleepTimeMs: Long
    private val maxSleepMs: Int
    override fun allowRetry(retryCount: Int): Boolean {
        return retryCount < maxRetries
    }

    override fun getSleepTimeMs(retryCount: Int): Long {
        var count = retryCount
        require(count >= 0) { "retries count must greater than 0." }
        if (count > MAX_RETRIES_LIMIT) {
            println(String.format("maxRetries too large (%d). Pinning to %d", maxRetries, MAX_RETRIES_LIMIT))
            count = MAX_RETRIES_LIMIT
        }
        var sleepMs = baseSleepTimeMs * 1.coerceAtLeast(random.nextInt(1 shl count))
        if (sleepMs > maxSleepMs) {
            println(String.format("Sleep extension too large (%d). Pinning to %d", sleepMs, maxSleepMs))
            sleepMs = maxSleepMs.toLong()
        }
        return sleepMs
    }

    companion object {
        private const val MAX_RETRIES_LIMIT = 29
        private const val DEFAULT_MAX_SLEEP_MS = Int.MAX_VALUE
    }

    init {
        this.baseSleepTimeMs = baseSleepTimeMs.toLong()
        this.maxSleepMs = maxSleepMs
    }
}